/*
* TestValidator.java
*
* Created on October 25, 2006
* Latest version: October 25, 2006
*
* This class is a part of the Assessment of Comprehension program (AoC), created
* for the Language Science Lab at Boston University, under the grant entitled
* "Assessment of Comprehension Skills in Older Struggling Readers." Please
* direct any questions regarding the project to Gloria S. Waters or David N.
* Caplan.
*
* This program was written by Sam Fentress [add any subsequent authors here].
* Questions about the program may be directed to sfentress@gmail.com.
*
* This program is released WITHOUT COPYRIGHT into the PUBLIC DOMAIN. This
* program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* @author Sam Fentress
* @version 0.05
*/
package engine;
import gui.Gui;
import sam.fileprocessing.Folders;
import sam.utilities.xml.myXML;
import sam.utilities.ArrayUtils;
import sam.utilities.Logger;
import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.io.FileReader;
import java.io.BufferedReader;
/**
* Checks stimulus files for errors. Checks to see that all image and sound files requested by the stim files exist and are in the right places.
* @author Sam Fentress
* @version 0.01
*/
public class TestValidator {
boolean areTestsOk;
String statusMessage, errorMessage;
File xmlFile;
/** Creates a new instance of TestValidator */
public TestValidator() {
statusMessage = ""; errorMessage = "";
xmlFile = null;
}
/**
* Runs through all stim files and checks for accuracy.
* @return True if all stim files are well-formatted and image and sound files exist.
*/
public boolean validateTests(){
areTestsOk = true;
File[] stimFiles = Folders.getFilesFromFolder("Stimuli","csv",true);
int numFiles = stimFiles.length;
try{
myXML test = new myXML("test");
test.setXMLComment("<!-- Validation file for Assessment Of Comprehension program, v. 0.05.3 or later -->");
for (int i = 0; i < stimFiles.length; i++) {
myXML subtest = test.addElement("subtest");
myXML name = subtest.addElement("name",stimFiles[i].getName());
myXML update = subtest.addElement("last_updated",new Long(stimFiles[i].lastModified()));
boolean isTestOk = validateFile(stimFiles[i]);
if (!isTestOk)
areTestsOk = false;
myXML valid = subtest.addElement("valid", new Boolean(isTestOk));
}
new File("Documents").mkdirs();
PrintWriter pw = new PrintWriter(new FileWriter("Documents" + File.separator + "validation.xml"), true);
test.serialize(pw);
} catch (myXML.myXMLException e){
areTestsOk = false;
errorMessage += "Could not create XML file";
Logger.log(e.toString());
} catch (java.io.IOException e){
areTestsOk = false;
errorMessage += "Could not create FileWriter or BufferedWriter";
Logger.log(e.toString());
}
if (areTestsOk)
statusMessage = "Success! Tests are all valid";
else statusMessage = "Warning: Errors were found in one or more tests";
return areTestsOk;
}
/**
* Checks individual stim file.
* @param file Filename of stim file to be checked.
* @return True if stim file is well-formatted and image and sound files exist.
*/
public boolean validateFile(File file){
boolean isFileOk = true;
try {
ValueList list = new ValueList(file);
list.setName(file.getName());
boolean isTypeOk = Gui.checkType(list.getType());
Logger.log(list.getName() + " checking type");
if (!isTypeOk){
errorMessage += " - The test type \"" + list.getType() + "\" in " + file.getName() + " is not a valid test type.\n";
isFileOk = false;
}
if (list.hasSound()){
Logger.log(list.getName() + " checking sound");
int numStimuli = 0;
if ((list.getType().toLowerCase().indexOf("one_word") == 0) ||
(list.getType().toLowerCase().indexOf("one_sent") == 0) ||
(list.getType().toLowerCase().indexOf("para") == 0))
numStimuli = 1;
else if (list.getType().toLowerCase().indexOf("two_words") == 0)
numStimuli = 2;
// need to have _mw_
if (list.hasExamples()){
for (int i = 0; i < list.getNumExamples(); i++) {
for (int j = 0; j < numStimuli; j++) {
String soundFile = list.getExamplesNo(i)[j];
File f = new File("Sounds" + File.separator + soundFile);
if (!(list.getType().toLowerCase().indexOf("para") == 0) && !(soundFile.toLowerCase().endsWith(".wav")))
if (!f.exists()){
errorMessage += " - The sound \"" + soundFile + ",\" used in " + file.getName() + ", could not be found in \\Sounds\n";
isFileOk = false;
}
}
}
}
int startStimNumber = 0;
if (list.hasTags())
startStimNumber += list.getNumTags();
for (int i = 0; i < list.getNumValues(); i++) {
for (int j = startStimNumber; j < numStimuli+startStimNumber; j++) {
String soundFile = list.getValueNo(i)[j];
File f = new File("Sounds" + File.separator + soundFile);
if (!(list.getType().toLowerCase().indexOf("para") == 0) && !(soundFile.toLowerCase().endsWith(".wav")))
if (!f.exists()){
errorMessage += " - The sound \"" + soundFile + ",\" used in " + file.getName() + ", could not be found in \\Sounds\n";
isFileOk = false;
}
}
}
}
if (list.getType().toLowerCase().indexOf("two_picts") > 0){
if (list.hasExamples()){
for (int i = 0; i < list.getNumExamples(); i++) {
String[] imageFiles = list.getExamplesNo(i);
for (int j = imageFiles.length - 2; j < imageFiles.length; j++) {
String imageFile = imageFiles[j];
File f = new File("Images" + File.separator + imageFile);
if (!f.exists()){
errorMessage += " - The image \"" + imageFile + ",\" used in " + file.getName() + ", could not be found in \\Images\n";
isFileOk = false;
}
}
}
}
for (int i = 0; i < list.getNumValues(); i++) {
String[] imageFiles = list.getValueNo(i);
Logger.log(ArrayUtils.toString(imageFiles));
for (int j = imageFiles.length - 2; j < imageFiles.length; j++) {
String imageFile = imageFiles[j];
File f = new File("Images" + File.separator + imageFile);
if (!f.exists()){
errorMessage += " - The image \"" + imageFile + ",\" used in " + file.getName() + ", could not be found in \\Images\n";
isFileOk = false;
}
}
}
}
} catch (ArrayIndexOutOfBoundsException e){
errorMessage += " - " + file.getName() + " is not properly formatted.\nMake sure to include both a Test Type and the " +
"test's instructions. Read the user manual for instructions on how to format a test.\n";
isFileOk = false;
StackTraceElement[] trace = e.getStackTrace();
Logger.log(e + " at " + trace[0].toString() + ", " + trace[1].toString() + ", " + trace[2].toString());
}
// String instructions = list.getInstructions();
// if (instructions.length() )
return isFileOk;
}
/**
* Reads validation XML file, checks to see that it is up-to-date, and, if up-to-date, whether all stim files were well-formatted.
* @return True if XML validation file exists, it is up-to-date, and all stim files were well-formatted.
*/
public boolean checkValidation(){
areTestsOk = true;
myXML xmlRoot;
File xmlFile = new File("Documents" + File.separator + "validation.xml");
if (xmlFile.exists()){
try{
BufferedReader in = new BufferedReader(new FileReader("Documents" + File.separator + "validation.xml"));
xmlRoot = new myXML((BufferedReader)in);
} catch (Exception e){
statusMessage = "Warning: Could not read validation file";
return false;
}
} else{
areTestsOk = false;
statusMessage = "Warning: Tests have not yet been validated.";
return false;
}
File[] stimFiles = Folders.getFilesFromFolder("Stimuli","csv",true);
int numFiles = stimFiles.length;
for (int i = 0; i < stimFiles.length; i++) {
long lastUpdated = stimFiles[i].lastModified();
myXML xmlSubtest = xmlRoot.getElement(i);
myXML xmlLastUpdated = xmlSubtest.findElement("last_updated");
if (lastUpdated > Long.parseLong(xmlLastUpdated.getValue())){
statusMessage = "Warning: Validation is not up to date.";
return false;
}
myXML xmlValid = xmlSubtest.findElement("valid");
if (xmlValid.getValue().equalsIgnoreCase("false")){
statusMessage = "Warning: Errors were found in one or more tests";
return false;
}
}
statusMessage = "Tests have been validated and are up to date";
return areTestsOk;
}
/**
*
* @return String describing status of validation to the user.
*/
public String getStatus(){return statusMessage;}
/**
*
* @return String describing error message to user.
*/
public String getErrorMessage(){return errorMessage;}
public void clearErrorMessage(){errorMessage = "";}
/**
* Checks to see if student has already started test, by comparing student name with name on saved data files. If student has taken test, program will re-start from last sub-test.
* @param student Student currently taking test
* @return True if student has already started the test.
*/
public static boolean checkIfAlreadyBegun(Student student){
String studentFilenameBegining = student.getLastName() +
student.getFirstName().substring(0,1);
File[] studentResults = Folders.getFilesBeginningWith("Results" + File.separator + studentFilenameBegining, studentFilenameBegining, "csv");
if (studentResults.length > 0)
return true;
else return false;
}
}